package com.vogelsk.archangelsk;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.image.ByteLookupTable;
import java.awt.image.ColorConvertOp;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageProducer;
import java.awt.image.LookupOp;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.imageio.ImageIO;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.Timer;

import com.sun.org.apache.bcel.internal.generic.NEW;
import com.vogelsk.archangelsk.ai.Commander;
import com.vogelsk.archangelsk.creatures.Apple;
import com.vogelsk.archangelsk.creatures.Bullet;
import com.vogelsk.archangelsk.creatures.GenericCreature;
import com.vogelsk.archangelsk.creatures.Tank;
import com.vogelsk.archangelsk.creatures.Wall;
import com.vogelsk.archangelsk.creatures.util.Command;
import com.vogelsk.archangelsk.creatures.util.Direction;
import com.vogelsk.archangelsk.gui.GreenRedSwapFilter;
import com.vogelsk.archangelsk.gui.TankImage;
import com.vogelsk.archangelsk.media.SoundManager;

@SuppressWarnings(value = { "all" })
public class Tanks extends JPanel implements ActionListener {

	private final int WIDTH = 700;
	private final int HEIGHT = 700;
	private final int DOT_SIZE = 10;
	private final int DELAY = 200;

	private Tank playerTank;
	private GreenRedSwapFilter filter = new GreenRedSwapFilter();
	private List<Tank> enemyTanks = new ArrayList<Tank>();
	private List<Bullet> bullets = new ArrayList<Bullet>();
	private List<Wall> structures = new ArrayList<Wall>();
	private Commander ai = new Commander();

	private int points;
	private SoundManager soundManager;

	private boolean inGame = true;
	JToggleButton tglbtnNewToggleButton = new JToggleButton("toggle sound");
	private Timer timer;
	private Image bulletImage;
	private Image appleImage;
	private Image wallImage;
	private TankImage playerTankImage;
	private TankImage enemyTankImage;
	
	private Image backgoround;
	private ImageIcon iitankUp;
	private ImageIcon iitankLeft;
	private ImageIcon iitankRight;
	private ImageIcon iitankDown;
	private ImageIcon wallIcon;
	private ImageIcon destroyedWallIcon;
	

	
	


	public Tanks() {
		soundManager = new SoundManager();
		
		byte lut[] = new byte[256];
        for (int j=0; j<256; j++) {
            lut[j] = (byte)(256-j); 
        }
        ByteLookupTable blut = new ByteLookupTable(0, lut); 
       
		initGame();
		addKeyListener(new TAdapter());
		addMouseListener(new MAdapter());
		ImageIcon bck = new ImageIcon(getClass().getResource(
				"/archangelsk/desert-texture.jpeg"));
		backgoround = bck.getImage();
		setBackground(Color.black);

		ImageIcon iid = new ImageIcon(getClass().getResource(
				"/archangelsk/red_dot.png"));
		bulletImage = iid.getImage();

		ImageIcon iia = new ImageIcon(getClass().getResource(
				"/archangelsk/apple.gif"));
		appleImage = iia.getImage();

		iitankUp = new ImageIcon(getClass().getResource(
				"/archangelsk/TankU.gif"));

		iitankLeft = new ImageIcon(getClass().getResource(
				"/archangelsk/TankL.gif"));

		iitankRight = new ImageIcon(getClass().getResource(
				"/archangelsk/TankR.gif"));

		iitankDown = new ImageIcon(getClass().getResource(
				"/archangelsk/TankD.gif"));
		
		wallIcon = new ImageIcon(getClass().getResource(
				"/archangelsk/brick.jpg"));
		destroyedWallIcon = new ImageIcon(getClass().getResource(
		"/archangelsk/brickdestroyed.gif"));
		wallImage = wallIcon.getImage();
		setFocusable(true);
		timer = new Timer(DELAY, this);
		timer.start();

		tglbtnNewToggleButton.setBounds(550, 0, 121, 23);
		tglbtnNewToggleButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				
				soundManager.toggle(tglbtnNewToggleButton.isSelected());
				 
			}
		});
		this.add(tglbtnNewToggleButton);
		tglbtnNewToggleButton.setFocusable(false);

	}

	public void initGame() {
		setTank();
		initEnemies();
		initWalls(23,true);
		initWalls(23,false);
		ai.setTanks(enemyTanks);
		ai.setTarget(playerTank);
		points = 0;
		soundManager.init();
		soundManager.toggle(tglbtnNewToggleButton.isSelected());
		URL url;
		url = getClass().getResource("/archangelsk/TankR.gif");
		
		Image tankRightImage = Toolkit.getDefaultToolkit().getImage(url);
		url = getClass().getResource("/archangelsk/TankL.gif");
		Image tankLeftImage = Toolkit.getDefaultToolkit().getImage(url);
		url = getClass().getResource("/archangelsk/TankU.gif");
		Image tankUpImage = Toolkit.getDefaultToolkit().getImage(url);
		url = getClass().getResource("/archangelsk/TankD.gif");
		Image tankDownImage = Toolkit.getDefaultToolkit().getImage(url);
		url = getClass().getResource("/archangelsk/boom.gif");
		Image tankDestroyedImage = Toolkit.getDefaultToolkit().getImage(url);
		

		ImageProducer  filteredSrc = new FilteredImageSource(tankDownImage.getSource(), filter);
		Image enemyTankDownImage = Toolkit.getDefaultToolkit().createImage(filteredSrc);
		
		filteredSrc = new FilteredImageSource(tankUpImage.getSource(), filter);
		Image enemyTankUpImage = Toolkit.getDefaultToolkit().createImage(filteredSrc);
		filteredSrc = new FilteredImageSource(tankRightImage.getSource(), filter);
		Image enemyTankRightImage = Toolkit.getDefaultToolkit().createImage(filteredSrc);
		filteredSrc = new FilteredImageSource(tankLeftImage.getSource(), filter);
		Image enemyTankLeftImage = Toolkit.getDefaultToolkit().createImage(filteredSrc);
		
		playerTankImage = new TankImage(tankLeftImage, tankRightImage, tankUpImage, tankDownImage,tankDestroyedImage);
		enemyTankImage = new TankImage(enemyTankLeftImage, enemyTankRightImage, enemyTankUpImage, enemyTankDownImage,tankDestroyedImage);
	}


	public synchronized void paint(Graphics g) {
		super.paint(g);
		Graphics2D g2d = (Graphics2D)g;
		if (inGame) {

			g2d.drawImage(backgoround,50,50,700,700,this);

			if (!getStructures().isEmpty()) {
				for (Wall wall : getStructures())
					if (wall != null){
						if(wall.isDestroyed()) wallImage = destroyedWallIcon.getImage();
						else wallImage = wallIcon.getImage();
						
						g2d.drawImage(wallImage, wall.getX(), wall.getY(),
								this);
						}
			}
			g2d.drawImage(playerTankImage.getCurrentImage(playerTank), playerTank.getX(),
					playerTank.getY(), this);

			if (!getEnemyTanks().isEmpty()) {

				for (Tank enemy : getEnemyTanks()) {
					g2d.drawImage( enemyTankImage.getCurrentImage(enemy), enemy.getX(), enemy.getY(),this);
				}
			}
			if (!getBullets().isEmpty()) {
				for (Bullet bullet : getBullets())
					if (bullet != null)
						g2d.drawImage(bulletImage, bullet.getX(), bullet.getY(),
								this);
			}


			g2d.setColor(Color.red);
			g2d.drawString("Tanks killed: " + points, 0, 780);
			Toolkit.getDefaultToolkit().sync();
			g2d.dispose();

		} else {
			gameOver(g2d);
		}
	}

	public void gameOver(Graphics g) {
		String msg;
		if (points==4){msg = "Congratulations, you won! - Click to play again";}
		else{ msg = "Game Over - Click to play again";}
		Font small = new Font("Helvetica", Font.BOLD, 14);
		FontMetrics metr = this.getFontMetrics(small);

		g.setColor(Color.white);
		g.setFont(small);
		g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2);
		soundManager.close();
	}
	public BufferedImage colorImage(BufferedImage loadImg, int red, int green, int blue) {
	    BufferedImage img = new BufferedImage(loadImg.getWidth(), loadImg.getHeight(),
	        BufferedImage.TRANSLUCENT);

	    Color newColor = new Color(red, green, blue, 0 /* alpha needs to be zero */);
		return img;

	}
	
	public BufferedImage tint(BufferedImage img) {

		BufferedImage image = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
		image.setData(img.getData());
	    for (int x = 0; x < image.getWidth(); x++) {
	        for (int y = 0; y < image.getHeight(); y++) {

	            Color color = new Color(image.getRGB(x, y));

	            // do something with the color :) (change the hue, saturation and/or brightness)
	            // float[] hsb = new float[3];
	            // Color.RGBtoHSB(color.getRed(), old.getGreen(), old.getBlue(), hsb);

	            // or just call brighter to just tint it
	            Color brighter = new Color(color.getRed()+5,color.getGreen(),color.getBlue(),color.getAlpha());

	            image.setRGB(x, y, brighter.getRGB());
	            
	        }
	    }
	    return image;
	}
	

	public synchronized void checkGridCollision(Tank tank) {

		if ((tank.getY() > HEIGHT) || (tank.getY() < 0)
				|| (tank.getX() > WIDTH) || (tank.getX() < 0)) {

			tank.revertMove();
		}
	}
	public synchronized void checkWallCollision(Tank tank) {
		for (Wall wall : getStructures()) {
			
		if (!wall.isDestroyed()&&(((tank.getY() > wall.getY()-15) && (tank.getY() < wall.getY()+15))
				&& ((tank.getX() > wall.getX()-15) && (tank.getX() < wall.getX()+15)))) {

			tank.revertMove();
		}
		}
	}
	public synchronized void checkCollision() {

		for (Tank enemyTank : enemyTanks) {

			checkGridCollision(enemyTank);
			checkWallCollision(enemyTank);
		}

		List<Bullet> toRemove = new ArrayList<Bullet>();

		if (!getBullets().isEmpty()) {

			for (Bullet bullet : getBullets()) {

				List<GenericCreature> targets = new ArrayList<GenericCreature>();
				targets.addAll(getStructures()); 		

					if (bullet.getParent().getTeam().equals(Tank.TEAM_A)) {
						targets.addAll(getEnemyTanks());
					} else
							targets.add(playerTank);

						for(GenericCreature target : targets){
					if ((bullet.getX() <= target.getX() + 40)
							&& (bullet.getX() >= target.getX())
							&& (bullet.getY() <= target.getY() + 40)
							&& (bullet.getY() >= target.getY())) {
						if(!target.isDestroyed()){
						soundManager.play(SoundManager.HIT_CLIP);
						if (target.isDestructable()) {

						if (target.equals(playerTank)) {

							inGame = false;
							} 
						else if (!(target instanceof Wall)) {

							points++;
							if (points==4) inGame = false;
							}
						target.setDestroyed(true);
						}
						toRemove.add(bullet);
						bullet.getParent().setShotFired(false);
					}
					}
						}
					if ((bullet.getY() > HEIGHT) || (bullet.getY() < 0)
							|| (bullet.getX() > WIDTH) || (bullet.getX() < 0)) {
						toRemove.add(bullet);
						bullet.getParent().setShotFired(false);
					}

				}
			bullets.removeAll(toRemove);
		}

	}

	public void setTank() {
		playerTank = new Tank(50, 50, Direction.UP, Tank.TEAM_A);
	}



	public  synchronized void actionPerformed(ActionEvent e) {

		if (inGame) {
			checkCollision();
			checkFire();
			ai.command();

		}
		repaint();
	}

	private synchronized void checkFire() {
		for (Bullet bullet : getBullets()) {
			bullet.move();}
	for (Tank enemyTank : getEnemyTanks()) {
			if (!enemyTank.isShotFired()&&!enemyTank.isDestroyed()
					&& enemyTank.getOrder().equals(Command.SUPPORT_FIRE)) {
				getBullets().add(enemyTank.fire());
			} else {
				enemyTank.manuouver();
			}
		}

	}
	
	public void initWalls(int length, boolean isHorizontal) {
		for (int i = 0; i < length;i++){
			if(isHorizontal){
		getStructures().add(new Wall(i*30+50, 400));}
			else getStructures().add(new Wall(400,i*30+50 ));
		}
	}
	public void initEnemies() {
		if(!getEnemyTanks().isEmpty()){
			getEnemyTanks().clear();
		}
				
		getEnemyTanks().add(new Tank(350, 500, Direction.UP, Tank.TEAM_B));
		getEnemyTanks().add(new Tank(250, 500, Direction.UP, Tank.TEAM_B));
		getEnemyTanks().add(new Tank(150, 500, Direction.UP, Tank.TEAM_B));
		getEnemyTanks().add(new Tank( 50, 500, Direction.UP, Tank.TEAM_B));

	}
	
	public List<Wall> getStructures() {
		return structures;
	}
	public void setStructures(List<Wall> structures) {
		this.structures = structures;
	}
	public void setEnemyTanks(List<Tank> enemyTanks) {
		this.enemyTanks = enemyTanks;
	}

	public  List<Tank> getEnemyTanks() {
		return enemyTanks;
	}

	public void setBullets(List<Bullet> bullets) {
		this.bullets = bullets;
	}

	public List<Bullet> getBullets() {
		return bullets;
	}

	private class TAdapter extends KeyAdapter {

		public synchronized void keyPressed(KeyEvent e) {

			int key = e.getKeyCode();
			if ((key == KeyEvent.VK_SPACE)) {
				if (!playerTank.isShotFired()) {
					getBullets().add(playerTank.fire());
					soundManager.play(SoundManager.SHOT_CLIP);
				}
				return;
			}
			if (key == KeyEvent.VK_LEFT) {
				playerTank.rotate(Direction.LEFT);
			}

			if (key == KeyEvent.VK_RIGHT) {
				playerTank.rotate(Direction.RIGHT);
			}

			if (key == KeyEvent.VK_UP) {
				playerTank.rotate(Direction.UP);
			}

			if (key == KeyEvent.VK_DOWN) {
				playerTank.rotate(Direction.DOWN);
			}

			playerTank.move();
			checkWallCollision(playerTank);
			checkGridCollision(playerTank);
		}

	}

	private class MAdapter extends MouseAdapter {

		public void mouseClicked(MouseEvent e) {
			if (!inGame) {
				inGame = true;
				initGame();
				repaint();
			}
		}

	}
}
